﻿using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System.IO;
using ZyGame.Execute;
using System;

namespace ZyGame.Resource
{
    internal class LoadingManager : Singleton<LoadingManager>
    {
        private Dictionary<string, LoadingBundleRunnable> runnables = new Dictionary<string, LoadingBundleRunnable>();
        internal static LoadingBundleRunnable Completed = new LoadingBundleRunnable();

        internal BundleRefrence LoadSync(PackageInfo package)
        {
            BundleRefrence result = default;
            PackageInfo[] dependcies = PackageInfo.GetDependciesPackages(package);
            Client.Console.WriteLine("Load Package List:" + string.Join(",", dependcies.Select(x => x.name)));
            List<AssetBundle> bundles = new List<AssetBundle>();
            for (int i = 0; i < dependcies.Length; i++)
            {
                if (!Client.File.Exists(dependcies[i].name, dependcies[i].version, dependcies[i].crc))
                {
                    Client.Console.WriteError("本地不存在文件：" + string.Format("{0} {1} {2}", dependcies[i].name, dependcies[i].version, dependcies[i].crc));
                    return default;
                }

                byte[] bytes = Client.File.ReadData(dependcies[i].name, dependcies[i].version, dependcies[i].crc);
                if (bytes is null || bytes.Length is 0)
                {
                    Client.Console.WriteError("读取文件失败：" + string.Format("{0} {1} {2}", dependcies[i].name, dependcies[i].version, dependcies[i].crc));
                    return default;
                }

                AssetBundle bundle = AssetBundle.LoadFromMemory(bytes);
                if (bundle is null)
                {
                    Client.Console.WriteError("加载资源包失败：" + string.Format("{0} {1} {2}", dependcies[i].name, dependcies[i].version, dependcies[i].crc));
                    return default;
                }

                bundles.Add(bundle);
            }

            for (int i = 0; i < bundles.Count; i++)
            {
                BundleRefrence refrence = new BundleRefrence(bundles[i]);
                if (bundles[i].name.Equals(package.name))
                {
                    result = refrence;
                }

                RefrenceManager.instance.Enqueue(refrence);
            }

            return result;
        }

        internal LoadingBundleRunnable LoadAsync(PackageInfo package)
        {
            if (!runnables.TryGetValue(package.name, out LoadingBundleRunnable runnable))
            {
                PackageInfo[] loadList = PackageInfo.GetDependciesPackages(package);
                runnables.Add(package.name, runnable = LoadingBundleRunnable.Create(package.name, loadList));
                Client.Console.WriteLine("Load Package List:" + string.Join(",", loadList.Select(x => x.name)));
            }

            return runnable;
        }

        internal void Remove(string name)
        {
            runnables.Remove(name);
        }

        internal LoadingBundleRunnable LoadNetAsync(string url, uint version, uint crc)
        {
            string bundleName = Path.GetFileName(url);
            if (!runnables.TryGetValue(bundleName, out LoadingBundleRunnable runnable))
            {
                PackageInfo package = new PackageInfo()
                {
                    name = url,
                    version = version,
                    crc = crc,
                    module = string.Empty,
                    files = new List<string>(),
                    dependencies = new List<string>(),
                };
                runnables.Add(bundleName, runnable = LoadingBundleRunnable.Create(bundleName, package));
                Client.Console.WriteLine("Load Network Package:" + bundleName);
            }

            return runnable;
        }

        internal LoadingBundleRunnable LoadMoudlePackages(string moudle)
        {
            if (!runnables.TryGetValue(moudle, out LoadingBundleRunnable runnable))
            {
                List<PackageInfo> packages = PackageInfo.GetModulePackages(moudle);
                List<PackageInfo> loadList = new List<PackageInfo>();
                foreach (var item in packages)
                {
                    foreach (var temp in PackageInfo.GetDependciesPackages(item))
                    {
                        if (loadList.Contains(temp))
                        {
                            continue;
                        }

                        loadList.Add(temp);
                    }
                }

                runnables.Add(moudle, runnable = LoadingBundleRunnable.Create(moudle, loadList.ToArray()));
                Client.Console.WriteLine("Load " + moudle + " Package List:" + string.Join(",", loadList));
            }

            return runnable;
        }
    }
}